package com.aube.activity;

import android.content.Context;

import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.BasicNetwork;
import com.aube.model.HomeCategoryModel;
import com.aube.model.ModuleData;
import com.aube.model.ModuleItem;
import com.huyn.baseframework.dynamicload.DLClassInflate;
import com.huyn.baseframework.dynamicload.DLContentView;
import com.huyn.baseframework.dynamicload.DLLayout;
import com.huyn.baseframework.dynamicload.DynamicLoaderHelper;
import com.huyn.baseframework.dynamicload.PluginPackageManager;
import com.huyn.baseframework.model.ThemeModel;
import com.huyn.baseframework.net.BFJSONRequest;
import com.huyn.baseframework.net.HttpRequestLoader;
import com.huyn.baseframework.net.OpenApi;
import com.huyn.baseframework.net.PluginPkgLoader;
import com.huyn.baseframework.utils.Constant;
import com.huyn.baseframework.utils.FileMD5Verify;
import com.huyn.baseframework.utils.StorageUtil;
import com.huyn.baseframework.utils.StringUtils;
import com.huyn.baseframework.utils.UmengUtils;
import com.huyn.baseframework.utils.UserUtil;
import com.huyn.baseframework.utils.Utils;
import com.ryg.dynamicload.internal.DLPluginManager;
import com.ryg.dynamicload.internal.DLPluginPackage;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Observable;
import java.util.Observer;

/**
 * Created by huyaonan on 16/5/26.
 */
public class PluginLoader {

    private static final String TAG = PluginLoader.class.getSimpleName();

    private static PluginLoader mInstance;
    private Context mContext;

    private PluginPkgCount mPluginPkgCount;

    public Observer mPkgCountObserver;

    private boolean mPluginNeedUpdate = false;

    private PluginPackageManager mPluginPkgManager;

    private PluginLoader(Context context) {
        this.mContext = context;
        mPluginPkgManager = PluginPackageManager.getInstance();
    }

    public static synchronized PluginLoader getmInstance(Context context) {
        if(mInstance == null)
            mInstance = new PluginLoader(context);
        return mInstance;
    }

    public class PluginPkgCount extends Observable {

        private int mPluginPkgCount = 0;

        public PluginPkgCount(int count) {
            this.mPluginPkgCount = count;
        }

        public void countDown() {
            this.mPluginPkgCount--;
            Utils.Log(TAG, mPluginPkgCount + "...left to be done");
            if(mPluginPkgCount <= 0) {
                setChanged();
                notifyObservers();
            }
        }

    }

    public void getHomeModules(final IModuleStateListener listener) {
        mPkgCountObserver = new Observer() {
            @Override
            public void update(Observable observable, Object data) {
                if(mPluginNeedUpdate)
                    UmengUtils.reportUmengEvent(mContext, UmengUtils.PLUGIN_UPDATE);
                if(listener != null) {
                    listener.deliverResponse(null);
                }
            }
        };

        //强制切到测试服
//        SharedPrefUtil.getInstance(mContext).putString(SharedPrefUtil.API_PATH, OpenApi.ROUTER_TEST);
//        OpenApi.setRouter(OpenApi.ROUTER_TEST);

        HashMap<String, String> params = new HashMap<>();
        params.put(OpenApi.API_METHOD, OpenApi.MODULE_LIST);
        BFJSONRequest request = new BFJSONRequest(ModuleData.class, params, new Response.Listener<ModuleData>() {
            @Override
            public void onResponse(ModuleData response) {
                if(response != null && response.success() && response.size()>0) {
                    mPluginPkgCount = new PluginPkgCount(response.size());
                    mPluginPkgCount.addObserver(mPkgCountObserver);
                    for(final ModuleItem item : response.data) {
                        loadPluginFile(item);
                    }
                }
            }

            @Override
            public void onErrorResponse(VolleyError error) {

            }

            @Override
            public void onStart() {

            }
        });
        HttpRequestLoader.getInstance(mContext).startHttpLoader(request);
    }

    private void loadPluginFile(ModuleItem item) {
        try {
            String pkgName = mContext.getPackageName().replace(".", "_");
            String fileName = pkgName + "_" + item.getFileName();
            Utils.Log(TAG, "load plugin..." + fileName);
            boolean canUseSDCard = StorageUtil.checkSDWritePermission(mContext);
            Utils.sysout("-----sd permission ..." + canUseSDCard);
            File destFile = BasicNetwork.newPluginFile(fileName, canUseSDCard);
            Utils.sysout("-----target file..." + destFile.getPath());
            if (destFile.exists()) {
                Utils.sysout("-----check file..." + item.getFileName());
                boolean verifyResult = FileMD5Verify.md5sum(destFile, item.md5);
                if (verifyResult) {
                    Utils.sysout("-----verify..." + fileName);
                    installPlugins(item, destFile.getPath());
                    mPluginPkgCount.countDown();
                } else {
                    destFile.delete();
                    Utils.sysout("-----delete and start to download..." + fileName);
                    downloadPlugin(item, canUseSDCard);
                }
            } else {
                if(!copyPluginFromAssets(item)) {
                    Utils.Log(TAG, "load plugin..." + fileName + "___from network");
                    downloadPlugin(item, canUseSDCard);
                } else {
                    Utils.sysout("-----copy from assets success..." + fileName);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
//            if(mModuleListener != null)
//                mModuleListener.deliverNoAccessPermissionError();
        }
    }

    /**
     * 将episode_1.apk从assets文件夹拷贝到本地文件夹,同时文件名变为com_aube_xxx_episode_1.apk
     * @param item
     * @return
     */
    private boolean copyPluginFromAssets(ModuleItem item) {
        try {
            String pkgName = mContext.getPackageName().replace(".", "_");
            String fileName = pkgName + "_" + item.getFileName();
            InputStream is = mContext.getAssets().open(item.getFileName());
            if(is == null)
                return false;
            File destFile = BasicNetwork.newPluginFile(fileName);
            FileOutputStream fos = new FileOutputStream(destFile);
            byte[] buffer = new byte[1024];
            while (true) {
                int len = is.read(buffer);
                if (len == -1) {
                    break;
                }
                fos.write(buffer, 0, len);
            }
            is.close();
            fos.close();

            installPlugins(item, destFile.getPath());
            mPluginPkgCount.countDown();

            Utils.Log(TAG, "load plugin..." + fileName + "_from assets success");

            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    private void downloadPlugin(final ModuleItem item, boolean canUseSDCard) {
        mPluginNeedUpdate = true;
        PluginPkgLoader.getInstance(mContext).startPluginLoader(item.download, item.getFileName(), canUseSDCard, new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                boolean verifyResult = FileMD5Verify.md5sum(response, item.md5);
                if (verifyResult)
                    installPlugins(item, response);

                mPluginPkgCount.countDown();
                Utils.Log(TAG, "plugin.." + item.packagename + " download success at:" + response + ", verify " + (verifyResult ? "success" : "fail"));
            }

            @Override
            public void onErrorResponse(VolleyError error) {
                Utils.Log(TAG, "plugin.." + item.packagename + " download fail");
                try {
                    BasicNetwork.getCacheDir(Constant.GEWARA_TEMP);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                mPluginPkgCount.countDown();
            }

            @Override
            public void onStart() {

            }
        }, new Response.ProgressListener() {
            @Override
            public void onProgress(float t) {

            }
        });
    }

    private synchronized void installPlugins(ModuleItem item, String path) {
        Utils.sysout("install......." + item.modelCode);
        DLPluginPackage pkg = DLPluginManager.getInstance(mContext).loadApk(path);
        mPluginPkgManager.putModule(item.modelCode, pkg);
    }

    public boolean hasModule(String id) {
        return mPluginPkgManager.hasModule(id);
    }

    public DLPluginPackage getModule(String id) {
        return mPluginPkgManager.getModule(id);
    }

    public void getData(HashMap<String, String> paramsMaps, final IModuleStateListener listener) {
        HashMap<String, String> params = new HashMap<>();
        params.put(OpenApi.API_METHOD, OpenApi.HOME_DETAIL);
        if(paramsMaps != null)
            params.putAll(paramsMaps);
        BFJSONRequest request = new BFJSONRequest(HomeCategoryModel.class, params, new Response.Listener<HomeCategoryModel>() {
            @Override
            public void onResponse(HomeCategoryModel response) {
                if(listener != null) {
                    listener.deliverResponse(response);
                }
            }

            @Override
            public void onErrorResponse(VolleyError error) {

            }

            @Override
            public void onStart() {

            }
        });
        HttpRequestLoader.getInstance(mContext).startHttpLoader(request);
    }

    public DLLayout inflatePluginLayout(Context context, String modelCode, String clazzName, boolean isWidget) {
        try {
            if(StringUtils.isBlank(modelCode) || StringUtils.isBlank(clazzName))
                return null;
            DLPluginPackage pkg = getModule(modelCode);
            DLClassInflate inflate = DynamicLoaderHelper.loadTargetClass(context, pkg, clazzName);
            if(inflate == null)
                return null;
            String clazz = isWidget ? inflate.getWidgetClass() : inflate.getListItemClass();
            return DynamicLoaderHelper.loadTargetLayout(context, pkg, clazz);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public DLContentView inflateContentPluginLayout(Context context, String modelCode, String clazzName) {
        try {
            if(StringUtils.isBlank(modelCode) || StringUtils.isBlank(clazzName))
                return null;
            DLPluginPackage pkg = getModule(modelCode);
            return DynamicLoaderHelper.loadContentView(context, pkg, clazzName);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public DLLayout inflatePluginLayout(Context context, DLPluginPackage pkg, String clazzName, boolean isWidget) {
        try {
            DLClassInflate inflate = DynamicLoaderHelper.loadTargetClass(context, pkg, clazzName);
            if(inflate == null)
                return null;
            String clazz = isWidget ? inflate.getWidgetClass() : inflate.getListItemClass();
            return DynamicLoaderHelper.loadTargetLayout(context, pkg, clazz);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public void getSplashScreen(final Context context, final ISplashListener listener) {
        HashMap<String, String> maps = new HashMap<>();
        maps.put(OpenApi.API_METHOD, OpenApi.SPLASH_SCREEN);
        BFJSONRequest request = new BFJSONRequest(ThemeModel.class, maps, new Response.Listener<ThemeModel>() {
            @Override
            public void onResponse(ThemeModel response) {
                if(response != null && response.success()) {
                    mPluginPkgManager.updateTheme(response);
                    UserUtil.saveBasicShareDetails(context, response);
                    if(listener != null)
                        listener.deliverResponse(response);
                }
            }

            @Override
            public void onErrorResponse(VolleyError error) {

            }

            @Override
            public void onStart() {

            }
        });
        HttpRequestLoader.getInstance(context).startHttpLoader(request);
    }

    public ThemeModel getTheme() {
        return mPluginPkgManager.getTheme();
    }

    public interface IModuleStateListener {
        public void deliverResponse(HomeCategoryModel data);
    }

    public interface ISplashListener {
        public void deliverResponse(ThemeModel theme);
    }

}
